#!/bin/sh

# Supported Environment Variables:
#   - OPENGROK_STANDARD_ENV       Run Time Shell Environment (Shell Script)
#   - OPENGROK_CONFIGURATION      User Configuration (Shell Script)
#
# Supported Environment Variables for configuring the default setup:
#   - OPENGROK_DISTRIBUTION_BASE  Base Directory of the OpenGrok Distribution
#                                   - containing the opengrok.jar
#   - OPENGROK_JAR                Directly specify the opengrok.jar file
#                                 switch), default is
#                                 $OPENGROK_DISTRIBUTION_BASE/opengrok.jar
#   - JAVA_HOME                   Full Path to Java Installation Root
#   - JAVA                        Full Path to java binary (to enable 64bit JDK)
#   - JAVA_OPTS                   Java options (e.g. for JVM memory increase view
#   - READ_XML_CONFIGURATION      file with read only configuration
#                                   - determining the configuration

PROGNAME=`basename $0`

SCRIPT_DIRECTORY=`dirname "${0}"`
SCRIPT_DIRECTORY=`cd "${SCRIPT_DIRECTORY}"; pwd`

Usage()
{
    exec >&2
    echo ""
    echo "Usage: ${PROGNAME} <add|delete|match|list|empty|help> [--help] [--verbose] [-d]"
    echo "       ${PROGNAME} add <name> <pattern>"
    echo "       ${PROGNAME} delete <name>"
    echo "       ${PROGNAME} match <project name>"
    echo ""
    echo "  The script searches for the configuration in"
    echo "    READ_XML_CONFIGURATION files or"
    echo "    you can use the -i option."
    echo "  When no such file exists it uses an empty configuration."
    echo ""
    echo "  Optional environment variables:"
    echo "    OPENGROK_CONFIGURATION - location of your configuration"
    echo "      e.g. $ OPENGROK_CONFIGURATION=/var/opengrok/myog.conf ${0} ... "
    echo ""
    echo "    See the code for more information on configuration options /" \
        "variables"
    echo ""
}

CommonInvocation()
{
    ${DO} \
    ${JAVA} \
    ${JAVA_OPTS} \
    ${JAVA_CLASSPATH:+-classpath} ${JAVA_CLASSPATH} \
    ${MAIN_CLASS} \
    ${INPUT_FILE:+-i} ${INPUT_FILE:+"$INPUT_FILE"} \
    ${OUTPUT_FILE:+-o} ${OUTPUT_FILE:+"$OUTPUT_FILE"} \
    "${@}"
}

StdInvocation()
{
    CommonInvocation \
    ${NAME:+-n} ${NAME:+"$NAME"} \
    ${PATTERN:+-r} ${PATTERN:+"$PATTERN"} \
    ${PARENT:+-p} ${PARENT:+"$PARENT"} \
    ${MATCH:+-m} ${MATCH:+"$MATCH"} \
    ${LIST:+-l} \
    ${DELETE:+-d} \
    ${EMPTY:+-e} \
    "${@}"
}

CheckInputFile()
{
    if [ -n "$INPUT_FILE" ] && ( [ ! -e "$INPUT_FILE" ] || [ ! -f "$INPUT_FILE" ] )
    then
        echo "input file does not exist or is not readable"
        LocalUsage
        exit 5
    fi
}


OneArgument()
{
    if [ $# -gt 0 ]
    then
        echo "$1"
    fi
}

ExpectOption()
{  
    if [ $# -lt 2 ]
    then
        echo "Argument \"$1\" expects a value"
        exit 3
    fi
}

Info()
{
    if $VERBOSE
    then
        echo "Configuration loaded"
        echo "\tJAVA_HOME = "${JAVA_HOME}
        if [ -n "$JAVA_HOME" ]
        then
            echo "\tJAVA = $JAVA_HOME/bin/java"
        else
            echo "\tJAVA ="
        fi
        echo "\tJAVA_OPTS = "${JAVA_OPTS}
        echo "\tJAVA_CLASSPATH = "${JAVA_CLASSPATH}
        echo "\tOPENGROK_JAR = "${OPENGROK_JAR}
        echo "\tOPENGROK_CONFIGURATION = "${OPENGROK_CONFIGURATION}
        echo "\tOPENGROK_STANDARD_ENV = "${OPENGROK_STANDARD_ENV}
        echo "\tOPENGROK_DISTRIBUTION_BASE = "${OPENGROK_DISTRIBUTION_BASE}
        echo "\tREAD_XML_CONFIGURATION = "${READ_XML_CONFIGURATION}
        echo ""
        echo "Files used"
        echo "\tINPUT_FILE = "${INPUT_FILE:-empty configuration}
        echo "\tOUTPUT_FILE = "${OUTPUT_FILE:-standard output}
        echo "\tPATTERN = "${PATTERN:-$PATTERN}
        echo "\tNAME = "${NAME:-$NAME}
        echo "\tPARENT = "${PARENT:-$PARENT}
        echo ""
    fi
}

Progress()
{
    if $VERBOSE
    then
        echo "$@"
    fi
}

Match ()
{
    LocalUsage()
    {
        echo "Usage:"
        echo "${PROGNAME} match <project name> [-i|--input <file>] [-v|--verbose] [-d]"
        echo ""
        echo "  Lists which groups would match the project name (description)"
        echo ""
        echo "Options:"
        echo " -d option performs dry run with verbose mode"
        echo " -i option can be used for specifying the input file"
    }

    while [ $# -gt 0 ]
    do
        opt="$1"
        case $opt in
            -i|--input)
                ExpectOption "$@"
                shift
                INPUT_FILE=$(OneArgument "$@")
            ;;
            -d)
                DO=echo
                VERBOSE=true
            ;;
            -v|--verbose)
                VERBOSE=true
            ;;
            -h|--help)
                LocalUsage
                exit 0
            ;;
            -*)
                echo "Uknown option \"$opt\"" && LocalUsage && exit 5
            ;;
            *)
                if [ "x$MATCH" = "x" ]
                then
                    MATCH=$(OneArgument "$@")
                else
                    echo "match must be specified only once" && LocalUsage && exit 5
                fi
            ;;
        esac
        shift
    done

    [ -z "$MATCH" ] && echo "project name must be specified" && LocalUsage && exit 5

    CheckInputFile
    Info
    StdInvocation
}

List ()
{
    LocalUsage()
    {
        echo "Usage:"
        echo "${PROGNAME} list [-i|--input <file>] [-v|--verbose] [-d]"
        echo ""
        echo "  Lists the current configuration"
        echo ""
        echo "Options:"
        echo " -d option performs dry run with verbose mode"
        echo " -i option can be used for specifying the input file"
    }

    while [ $# -gt 0 ]
    do
        opt="$1"
        case $opt in
            -i|--input)
                ExpectOption "$@"
                shift
                INPUT_FILE=$(OneArgument "$@")
            ;;
            -d)
                DO=echo
                VERBOSE=true
            ;;
            -v|--verbose)
                VERBOSE=true
            ;;
            -h|--help)
                LocalUsage
                exit 0
            ;;
            -*)
                echo "Uknown option \"$opt\"" && LocalUsage && exit 5
            ;;
            *)
                echo "this requires no other parameter"
                LocalUsage
                exit 5
            ;;
        esac
        shift
    done

    LIST=true

    CheckInputFile
    Info
    StdInvocation
}

Empty ()
{
    LocalUsage()
    {
        echo "Usage:"
        echo "${PROGNAME} empty [-i|--input <file>] [-v|--verbose] [-d]"
        echo ""
        echo "  Creates an empty configuration. If the input file is specified"
        echo "  it directly outputs the given file."
        echo ""
        echo "Options:"
        echo " -d option performs dry run with verbose mode"
        echo " -i option can be used for specifying the input file"
    }

    while [ $# -gt 0 ]
    do
        opt="$1"
        case $opt in
            -i|--input)
                ExpectOption "$@"
                shift
                INPUT_FILE=$(OneArgument "$@")
            ;;
            -d)
                DO=echo
                VERBOSE=true
            ;;
            -v|--verbose)
                VERBOSE=true
            ;;
            -h|--help)
                LocalUsage
                exit 0
            ;;
            -*)
                echo "Uknown option \"$opt\"" && LocalUsage && exit 5
            ;;
            *)
                echo "this requires no other parameter"
                LocalUsage
                exit 5
            ;;
        esac
        shift
    done

    EMPTY=true

    CheckInputFile
    Info
    StdInvocation
}

Delete ()
{
    LocalUsage()
    {
        echo "Usage:"
        echo "${PROGNAME} delete <name> [-i|--input <file>] [-o|--output <file>] [-l] [-v|--verbose] [-u|--update] [-d]"
        echo ""
        echo "  Deletes a group with given name from the input configuration"
        echo ""
        echo "Options:"
        echo " -d option performs dry run with verbose mode"
        echo " -i option can be used for specifying the input file"
        echo " -l option prints the overview to stdout (still -o can be used)"
        echo " -o option can be used for saving the result"
        echo " -u option forces the script to use same output file as input file (overwrite)"
    }

    while [ $# -gt 0 ]
    do
        opt="$1"
        case $opt in
            -i|--input)
                ExpectOption "$@"
                shift
                INPUT_FILE=$(OneArgument "$@")
            ;;
            -o|--output)
                ExpectOption "$@"
                shift
                OUTPUT_FILE=$(OneArgument "$@")
            ;;
            -u|--update)
                OUTPUT_FILE="$INPUT_FILE"
            ;;
            -l|--list)
                LIST=true
            ;;
            -d)
                DO=echo
                VERBOSE=true
            ;;
            -v|--verbose)
                VERBOSE=true
            ;;
            -h|--help)
                LocalUsage
                exit 0
            ;;
            -*)
                echo "Uknown option \"$opt\"" && LocalUsage && exit 5
            ;;
            *)
                if [ "x$NAME" = "x" ]
                then
                    NAME=$(OneArgument "$@")
                else
                    echo "name must be specified only once" && LocalUsage && exit 5
                fi
            ;;
        esac
        shift
    done

    [ -z "$NAME" ] && echo "name must be specified" && LocalUsage && exit 5


    DELETE=true

    CheckInputFile
    Info
    StdInvocation
}

Add ()
{
    LocalUsage()
    {
        echo "Usage:"
        echo "${PROGNAME} add <name> <pattern> [-i|--input <file>] [-o|--output <file>] [-l] [-v|--verbose] [-u|--update] [-d]"
        echo ""
        echo "  Adds or updates a group with given name"
        echo "    1) If given group name already exists, the pattern is updated."
        echo "    2) If given group name does not exist, the group is inserted"
        echo "    3) If the parent group exists, the group is inserted as its child"
        echo ""
        echo "Options:"
        echo " -d option performs dry run with verbose mode"
        echo " -i option can be used for specifying the input file"
        echo " -l option prints the overview to stdout (still -o can be used)"
        echo " -o option can be used for saving the result"
        echo " -u option forces the script to use same output file as input file (overwrite)"
    }

    NAME=""
    PATTERN=""
    while [ $# -gt 0 ]
    do
        opt="$1"
        case $opt in
            -i|--input)
                ExpectOption "$@"
                shift
                INPUT_FILE=$(OneArgument "$@")
            ;;
            -o|--output)
                ExpectOption "$@"
                shift
                OUTPUT_FILE=$(OneArgument "$@")
            ;;
            -p|--parent)
                ExpectOption "$@"
                shift
                PARENT=$(OneArgument "$@")
            ;;
            -u|--update)
                OUTPUT_FILE="$INPUT_FILE"
            ;;
            -l|--list)
                LIST=true
            ;;
            -d)
                DO=echo
                VERBOSE=true
            ;;
            -v|--verbose)
                VERBOSE=true
            ;;
            -h|--help)
                LocalUsage
                exit 0
            ;;
            -*)
                echo "Uknown option \"$opt\"" && LocalUsage && exit 5
            ;;
            *)
                if [ "x$NAME" = "x" ]
                then
                    NAME=$(OneArgument "$@")
                elif [ "x$PATTERN" = "x" ]
                then
                    PATTERN=$(OneArgument "$@")
                else
                    echo "name and pattern must be specified only once" && LocalUsage && exit 5
                fi
            ;;
        esac
        shift
    done

    [ -z "$NAME" ] && echo "name must be specified" && LocalUsage && exit 5
    [ -z "$PATTERN" ] && echo "pattern must be specified" && LocalUsage && exit 5

    CheckInputFile
    Info
    StdInvocation
}


# Find and load relevant configuration
#
# Taken (and modified) from original OpenGrok shell wrapper
#
SetupInstanceConfiguration()
{
    VERBOSE="${VERBOSE:-false}"

    if [ -f "${OPENGROK_STANDARD_ENV}" ]
    then
        Progress "Loading ${OPENGROK_STANDARD_ENV} ..."
        . "${OPENGROK_STANDARD_ENV}"
    fi

    if [ -n "${OPENGROK_CONFIGURATION}" -a -f "${OPENGROK_CONFIGURATION}" ]
    then
        # Load the Local OpenGrok Configuration Environment
        Progress "Loading ${OPENGROK_CONFIGURATION} ..."
        . "${OPENGROK_CONFIGURATION}"
    fi

    # REQUIRED: Java Home
    JAVA_HOME="${JAVA_HOME:-`FindJavaHome`}"

    # REQUIRED: Java Virtual Machine
    JAVA="${JAVA:-$JAVA_HOME/bin/java}"

    if [ -z "${OPENGROK_DISTRIBUTION_BASE}" ]
    then
        if [ -d "${SCRIPT_DIRECTORY}/../dist" -a \
             -f "${SCRIPT_DIRECTORY}/../dist/opengrok.jar" -a \
             -f "${SCRIPT_DIRECTORY}/../dist/source.war" \
           ]
        then
            # Handle Developer Build Environments
            OPENGROK_DISTRIBUTION_BASE="${SCRIPT_DIRECTORY}/../dist"
        else
            # Handle Binary Distributions
            OPENGROK_DISTRIBUTION_BASE="${SCRIPT_DIRECTORY}/../lib"
        fi
    fi

    # REQUIRED: Java Archive of OpenGrok (Installation Location)
    OPENGROK_JAR="${OPENGROK_JAR:-${OPENGROK_DISTRIBUTION_BASE}/opengrok.jar}"

    JAVA_CLASSPATH="$CLASSPATH"
    JAVA_CLASSPATH="${JAVA_CLASSPATH}:${OPENGROK_JAR}"
    JAVA_OPTS="${JAVA_OPTS:--Xmx2048m}"
    MAIN_CLASS="org.opensolaris.opengrok.configuration.Groups"

    unset NAME
    unset PATTERN
    unset PARENT
    unset DELETE
    unset MATCH
    unset LIST

    if [ -n "$READ_XML_CONFIGURATION" ] && [ -f "$READ_XML_CONFIGURATION" ]
    then
            INPUT_FILE="$READ_XML_CONFIGURATION"
    fi
}

# Find java home based on your system information
#
# Taken from original OpenGrok shell wrapper
#
FindJavaHome()
{
    if [ -x "/bin/uname" ]; then
        OS_NAME="`/bin/uname -s`"
        OS_VERSION="`/bin/uname -r`"
    elif [ -x "/usr/bin/uname" ]; then
        OS_NAME="`/usr/bin/uname -s`"
        OS_VERSION="`/usr/bin/uname -r`"
    else
        echo "Cannot determine operating system version"
        exit 3
    fi

    javaHome=""
    case "${OS_NAME}:${OS_VERSION}" in
		SunOS:5.10) javaHome="/usr/jdk/instances/jdk1.7.0" ;;
		SunOS:5.11) javaHome="/usr/jdk/latest"             ;;
		SunOS:5.12) javaHome="/usr/jdk/latest"             ;;
		Darwin:*)   javaHome=`/usr/libexec/java_home`      ;;
		Linux:*)
        if [ -f /etc/alternatives/java ]
        then
           javaHome=`ls -l /etc/alternatives/java | cut -f 2 -d \> `
           javaHome=`dirname $javaHome`
           javaHome=`dirname $javaHome`
        fi
        ;;
    esac

    if [ -z "${javaHome}" ]
    then
        echo "Unable to determine Java Home" \
              "for ${OS_NAME} ${OS_VERSION}"
        exit 3
    fi

    if [ ! -d "${javaHome}" ]
    then
        echo "Missing Java Home ${javaHome}"
        exit 3
    fi

    echo "${javaHome}"
}


if [ $# -eq 0 ]
then
    Usage
    exit 1
fi

SetupInstanceConfiguration

case "${1}" in
    match)
        shift
        Match "$@"
    ;;
    delete)
        shift
        Delete "$@"
    ;;
    add)
        shift
        Add "$@"
    ;;
    list)
        shift
        List "$@"
    ;;
    empty)
        shift
        Empty "$@"
    ;;
    help)
        Usage
        exit 0
    ;;
    *)
        Usage
        exit 5
    ;;
esac
